/*
 * @(#)TypeUtils.java   1.0   May 7, 2007
 *
 * Copyright 2000-2007 ETH Zurich. All Rights Reserved.
 *
 * This software is the proprietary information of ETH Zurich.
 * Use is subject to license terms.
 *
 * @(#) $Id: TypeUtils.java 427 2007-05-19 23:35:07Z D\aldespin $
 */
package ch.ethz.globis.javaom.utils;

import ch.ethz.globis.javaom.core.AttributeValue;
import ch.ethz.globis.javaom.core.Bulk;
import ch.ethz.globis.javaom.core.Object;
import ch.ethz.globis.javaom.system.Metadata;

/**
 * @author aldespin
 * @version 1.0
 */
public class TypeUtils {

   public static Object create(final String typeName) {
      final Object result = new Object(Metadata.METADATA);
      // dress regularily with object and type
      result.dress(Metadata.METADATA.getTypeObject(Metadata.OBJECT));
      result.dress(Metadata.METADATA.getTypeObject(Metadata.TYPE));
      // set name attribute
      result
            .setAttributeValue(Metadata.METADATA.getAttributeObject(Metadata.TYPE, Metadata.NAME),
                  new AttributeValue<String>(Metadata.METADATA.getTypeObject(Metadata.STRING),
                        typeName));

      // we have to create an extent collection for it
      final Object extent = new Object();
      extent.dress(Metadata.METADATA.getTypeObject(Metadata.OBJECT));
      extent.dress(Metadata.METADATA.getTypeObject(Metadata.COLLECTION));
      extent.setAttributeValue(Metadata.METADATA.getAttributeObject(Metadata.COLLECTION,
            Metadata.NAME), new AttributeValue<String>(Metadata.METADATA
            .getTypeObject(Metadata.STRING), Metadata.getExtentCollectionName(typeName)));
      extent.setAttributeValue(Metadata.METADATA.getAttributeObject(Metadata.COLLECTION,
            Metadata.MEMBERTYPE), result);
      extent.setAttributeValue(Metadata.METADATA.getAttributeObject(Metadata.COLLECTION,
            Metadata.EXTENT), new Bulk());

      // register type with extent collection
      BinaryCollectionUtils.add(Metadata.METADATA.getBinaryCollection(Metadata.TYPE_HAS_EXTENT),
            result, extent);

      return result;
   }

   public static void declareTypeAttribute(final Object type, final Object attribute) {
      BinaryCollectionUtils.add(Metadata.METADATA
            .getBinaryCollection(Metadata.TYPE_HAS_ATTRIBUTES), type, attribute);
   }

   @SuppressWarnings("unchecked")
   public static AttributeValue<String> getName(final Object type) {

      final Bulk argumentHasAttributeValues = ObjectUtils.getAttributeValues(type);

      // get name attribute object
      final Object nameAttribute = Metadata.METADATA.getAttributeObject(Metadata.TYPE,
            Metadata.NAME);

      // get links of name attribute
      final Bulk nameValues = AttributeUtils.getAttributeValues(argumentHasAttributeValues,
            nameAttribute);

      // test if not empty
      if (nameValues.isEmpty()) {
         throw new RuntimeException("Type '" + type.toString()
               + "' given has no name attribute value");
      }
      // test if no more than one value
      if (nameValues.size() > 1) {
         throw new RuntimeException("Type '" + type.toString()
               + "' given has more than one name attribute value");
      }

      // return result
      try {
         return (AttributeValue<String>) nameValues.iterator().next();
      } catch (final ClassCastException e) {
         throw new RuntimeException("Type '" + type.toString()
               + "' given has a name attribute value of type '"
               + nameValues.iterator().next().getClass().getSimpleName()
               + "' instead of AttributeValue<String>");
      }
   }

   public static Object getExtentCollection(final Object type) {
      final Object typeHasExtent = Metadata.METADATA.getBinaryCollection(Metadata.TYPE_HAS_EXTENT);
      final Bulk extentCollections = BinaryCollectionUtils.range(BinaryCollectionUtils
            .domainSingleRestriction(typeHasExtent, type));
      if (extentCollections.isEmpty()) {
         throw new RuntimeException("Type '" + type.toString() + "' has no extent collection");
      }
      if (extentCollections.size() > 1) {
         throw new RuntimeException("Type '" + type.toString()
               + "' has more than one extent collection");
      }
      return extentCollections.iterator().next();
   }

}
